#ifndef ISOFILESYSTEM_H
#define ISOFILESYSTEM_H

#include "fs.h"
#include "metafs.h"

#include "fbd.h"

#define MAX_CHILD 255

#pragma pack(1)

typedef struct
{
    u8 size;
    u8 sectorsInExtendedRecord;
    u32 firstDataSectorLE;
    u32 firstDataSectorBE;
    u32 dataLengthLE;
    u32 dataLengthBE;
    u8 years;
    u8 month;
    u8 day;
    u8 hour;
    u8 minute;
    u8 second;
    u8 offsetFromGMT;
    u8 flags; /* 2 = directory */
    u8 fileUnitSize;
    u8 interleaveGap;
    u16 volSeqNumberLE;
    u16 volSeqNumberBE;
    u8 identifierLength; /* identifier comes right after */
    char firstIdChar;
} DirectoryEntry;

typedef struct
{
    DirectoryEntry entry;
    char space[2048 - sizeof(DirectoryEntry)];
} DirectorySector;

typedef struct
{
    u8 type;
    char cd001[6];
    u8 version;
    char sysid[32];
    char volid[32];
    u8 empty1[8];
    u32 numSectorsLE;
    u32 numSectoreBE;
    u8 empty2[32];
    u16 volSetSizeLE;
    u16 volSetSizeBE;
    u16 volSeqNumLE;
    u16 volSeqNumBE;
    u16 sectorSizeLE;
    u16 sectorSizeBE;
    u32 pathTableLengthLE;
    u32 pathTableLengthBE;
    u16 firstLETableSectorLE;
    u16 firstLETableSectorBE;
    u16 secondLETableSectorLE;
    u16 secondLETableSectorBE;
    u16 firstBETableSectorLE;
    u16 firstBETableSectorBE;
    u16 secondBETableSectorLE;
    u16 secondBETableSectorBE;
    DirectoryEntry root;
    char volumeSetIdentifier[128];
    char publisherIdentifier[128];
    char dataPreparerIdentifier[128];
    char applicationIdentifier[128];
    char copyrightFileIdentifier[37];
    char abstractFileIdentifier[37];
    char bibliographicalFileIdentifier[37];
    char volCreationDateTime[17];
    char mreModDateTime[17];
    char volExpireDateTime[17];
    char volEffectiveDateTime[17];
    u8 one;
    u8 zero;
    u8 reserved[512];
    u8 empty3[653];
} VolDescriptor;

#pragma pack()

struct TreeEntry
{
    char *name;
    s32 flags;
    s32 startingPosition;
    s32 size;
    s32 isDirectory;
    struct TreeEntry *children;
};

typedef struct TreeEntry TreeEntry;

typedef struct
{
    TreeEntry *file;
    u32 seekPos;
    u8 isRawSector;
    u32 sectorStart;
    u32 openSize;
} OpenFileEntry;

typedef struct
{
    OpenFileEntry entries[MAX_ENTRIES]; /* TODO: STATIC */
    u32 handles[MAX_ENTRIES]; /* TODO: STATIC */
    u32 nument;
    TreeEntry treeroot;
    FileBlockDevice blockDevice;

    TreeEntry entireISO;
} ISOFileSystem;

u8 iso_test(const char *fn);
void iso_init(ISOFileSystem *isofs, const char *filename);
void iso_free(System *fs);
void iso_readDirectory(ISOFileSystem *isofs, u32 startsector, u32 dirsize, TreeEntry *root);
FileInfo iso_getFileInfo(System *fs, const char *filename);
s32 iso_ownsHandle(System *fs, u32 handle);
size_t iso_readFile(System *fs, u32 handle, char *pointer, u32 size);
size_t iso_readFileToAddr(System *fs, u32 handle, u32 addr, u32 size);
s32 iso_openFile(System *fs, const char *filename, FileAccess access);
void iso_closeFile(System *fs, u32 handle);
u32 iso_seekFile(System *fs, u32 handle, s32 position, FileMove type);
u32 iso_getDirListing(System *fsc, const char *path, FileInfo **listing);
void iso_freeDirListing(FileInfo *listing);
void iso_printDirectory(TreeEntry *root, const char *dirname);
s32 iso_writeFile(System *fs, u32 handle, const char *pointer, u32 size);

#endif

